﻿using System;
using System.IO;
using System.Globalization;
using System.Web;
using System.Web.Caching;
using System.Linq;

using Fuse8.DomainFramework.Common;

namespace Fuse8.ContentManagementFramework.Web.FileMinifier
{
    public class FileBundle
    {
        private static FileBundle _instance = new FileBundle();
        private HttpContextBase _currentContext = null;

        public virtual HttpContextBase CurrentContext
        {
            get
            {
                return _currentContext == null ?
                    new HttpContextWrapper(HttpContext.Current) :
                    _currentContext;
            }
            set
            {
                _currentContext = value;
            }
        }

        public static string InsertFile(string relativePath)
        {
            return InsertFile(string.Empty, relativePath);
        }

        public static string InsertFile(string virtualDirectory, string relativePath)
        {
            return _instance.GetFile(virtualDirectory, relativePath);
        }

        protected virtual string GetFile(string virtualDirectory, string relativePath)
        {
            Guard.ArgumentNotEmpty(relativePath, "relativePath");

            string result = string.Empty;

            relativePath = !string.IsNullOrWhiteSpace(virtualDirectory) ?
                    string.Format("/{0}/assets/{1}", virtualDirectory, relativePath) :
                    string.Format("/assets/{0}", relativePath);                

            if (CurrentContext.Cache[relativePath] == null)
            {
                FileInfo[] files = FindFiles(CurrentContext.Server.MapPath(relativePath));
                DateTime lastModified = files.Length > 0 ? files.Max(f => f.LastWriteTime) : DateTime.MinValue;

                int index = relativePath.LastIndexOf('.');
                result = relativePath.Insert(index, string.Format("_{0}", lastModified.ToString("ddMMyyyy", CultureInfo.InvariantCulture)));

                if (files.Length > 0)
                {
                    string dependency = files.Length > 1 ? files[0].DirectoryName : files[0].FullName;
                    CurrentContext.Cache.Insert(relativePath, result, new CacheDependency(dependency));
                }
            }
            else
            {
                result = CurrentContext.Cache[relativePath].ToString();
            }

            return result;
        }

        internal static FileInfo[] FindFiles(string absoluteFileName)
        {
            Guard.ArgumentNotEmpty(absoluteFileName, "absoluteFileName");

            FileInfo[] result = null;

            if (File.Exists(absoluteFileName))
            {
                // Is file
                result = new[] { new FileInfo(absoluteFileName) };
            }
            else
            {
                // Is directory
                string dir = absoluteFileName.Replace(Path.GetExtension(absoluteFileName), string.Empty);
                result = new DirectoryInfo(dir).GetFiles(string.Format("*{0}", Path.GetExtension(absoluteFileName)));
                if ((result != null) && result.Any())
                {
                    result = result.OrderBy(p => p.Name, new CompareFileInfoEntries()).ToArray();
                }
            }

            return result;
        }
    }
}
